//
// Created by wsl on 2023/11/17.
//

#include "bsp_usart.h"


#include "bsp_usart.h"
#include "delay.h"

USART_TypeDef *DEBUG_printf_Usartx = DEBUG_Printf_USART;


/**
1-初始化串口需要用到的GPIO

2-初始化串口，USART_InitTypeDef

3-中断配置（接收中断，中断优先级）

4-使能串口

5-编写发送和接收函数

6-编写中断服务函数

 USART1_IRQHandler

 * */

#if IS_MDK            //MDK环境

/** 重定向c库函数fputc的流到串口，重定向后可使用printf函数（因为printf调用了fputc）*/
int fputc(int ch, FILE *f)
{
    /** 发送一个字节数据到串口 */
    USART_SendData(DEBUG_Printf_USART, (uint8_t)ch);

    /** 等待发送完毕 */
    while(USART_GetFlagStatus(DEBUG_Printf_USART, USART_FLAG_TXE) == RESET);

    //fgetc()
    return ch;
}

/** 重定向c库函数fgetc的流到串口，重定向后可使用scanf*/
int fgetc(FILE *f)
{
    /* 等待串口输入数据 */
    while (USART_GetFlagStatus(DEBUG_Printf_USART, USART_FLAG_RXNE) == RESET);

    return (int)USART_ReceiveData(DEBUG_Printf_USART);
}

#else                //GCC环境

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)

PUTCHAR_PROTOTYPE {
	/** 发送一个字节数据到串口 */
	USART_SendData(DEBUG_printf_Usartx, (uint8_t) ch);

	/** 等待发送完毕 */
	while (USART_GetFlagStatus(DEBUG_printf_Usartx, USART_FLAG_TC) == RESET);

	//fgetc()
	return ch;
}

GETCHAR_PROTOTYPE {
	/* 等待串口输入数据 */
	while (USART_GetFlagStatus(DEBUG_printf_Usartx, USART_FLAG_RXNE) == RESET);

	return (int) USART_ReceiveData(DEBUG_printf_Usartx);
}

int fputc(int ch, FILE *f) {
	/** 发送一个字节数据到串口 */
	USART_SendData(DEBUG_printf_Usartx, (uint8_t) ch);

	/** 等待发送完毕 */
	while (USART_GetFlagStatus(DEBUG_printf_Usartx, USART_FLAG_TXE) == RESET);

	//fgetc()
	return ch;
}

#endif

/** -------------------------- 串口1 -------------------------- */

/**
 * @brief 设置printf重定向的流
 *
 * @param Usartx 新的printf流
 *
 * @retval 无
 * */
void Usart_Set_Printf_Stream(USART_TypeDef *Usartx)
{
	DEBUG_printf_Usartx = Usartx;
}

/**
 * @brief 串口1 GPIO配置
 *
 * @retval 无
 * */
static void Usart1_Config()
{
	//串口1的GPIO时钟
	DEBUG_USART1_GPIO_APBxClkCmd(DEBUG_USART1_GPIO_CLK, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	// 串口1 Tx的GPIO配置为推挽复用输出模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART1_TX_GPIO_PIN;
	GPIO_Init(DEBUG_USART1_TX_GPIO_PORT, &GPIO_InitStructure);

	// 串口1 Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART1_RX_GPIO_PIN;
	GPIO_Init(DEBUG_USART1_RX_GPIO_PORT, &GPIO_InitStructure);
}

/**
 * @brief 串口1 初始化
 *
 * @param baudRate 串口1 的波特率设置
 *
 * @retval 无
 * */
void Usart1_Init(uint32_t baudRate)
{
	//判断是否为重定义printf的Usart
	if (DEBUG_printf_Usartx == DEBUG_USART1)
	{
#if !IS_MDK      //非MDK时的配置

		//缓冲区为0，一有数据就发
		setvbuf(stdout, NULL, _IONBF, 0);

#endif
	}

	USART_InitTypeDef USART_InitStructure;

	//打开串口1的时钟
	DEBUG_USART1_APBxClkCmd(DEBUG_USART1_CLK, ENABLE);

	// 配置串口1的工作参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;								// 配置 帧数据字长
	USART_InitStructure.USART_StopBits = USART_StopBits_1;									// 配置停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;										// 配置校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;			// 配置硬件流控制（无硬件流控制）
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;							// 配置工作模式，收发一起使能
	USART_InitStructure.USART_BaudRate = baudRate;											// 配置波特率

	USART_Init(DEBUG_USART1, &USART_InitStructure);

	//使能串口
	USART_Cmd(DEBUG_USART1, ENABLE);

	//初始化串口1的GPIO
	Usart1_Config();

	//当Usart1为printf重定义时，刷新输出缓冲区
	if (DEBUG_printf_Usartx == DEBUG_USART1)
	{
#if !IS_MDK      //非MDK时的配置

		printf("\n");   //刷新输出缓冲区【测试结果，根据实际需要更改】
#endif
	}
}

/**
 * @brief 使用串口1 发送一字节数据
 * @param data 发送的一字节数据
 * @return 无
 * */
void Usart1_SendByte(const uint8_t data) {
	/** 发送一个字节数据到USART */
	USART_SendData(DEBUG_USART1, data);

	/** 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(DEBUG_USART1, USART_FLAG_TXE) == RESET);
}

/**
 * @brief 使用串口1 发送两字节数据
 * @param data 发送的两字节数据 uint16_t
 * @return 无
 * */
void Usart1_Send2Byte(const uint16_t data) {
	//发送高八位数据
	Usart1_SendByte((data & 0xff00) >> 8);

	//发送低八位数据
	Usart1_SendByte(data & 0x00ff);
}

/**
 * @brief 使用串口1 发送数组
 * @param array 发送的数组
 * @param len array的元素个数 0 - len, 【len不可超过数组元素个数】
 * @return 无
 * */
void Usart1_SendArray(const uint8_t *array, uint32_t len) {
	uint32_t i = 0;
	//将数组中的数据全部发送
	for (i = 0; i < len; ++i) {
		Usart1_SendByte(array[i]);
	}

	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART1, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 发送字符串，遇到'\0'停止，发送出去的字符串末尾有'\0'
 * @param str 发送的字符串
 * @return 无
 * */
void Usart1_SendString(const uint8_t *str) {
	while (*str != '\0') {
		Usart1_SendByte(*str++);
	}
	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART1, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 等待接收一字节数据
 *
 * @retval 返回接收到的数据
 *
 * @note 如果未接收到将会等待接收一字节，这将会导致程序卡死。
 * 		 当接收到多字节数据时，会导致多余的字节滞留输出缓冲区，下次调用接收函数时，会接收到滞留的字节数据，且存在不确定性。
 * 		 不建议使用该函数，建议使用原版 USART_ReceiveData 配合 USART_GetFlagStatus 使用
 * */
uint8_t Usart1_ReceiveByte() {

#if 1
	static uint8_t temp;

	while (USART_GetFlagStatus(DEBUG_USART1, USART_FLAG_RXNE) == RESET);
	temp = (uint8_t) USART_ReceiveData(DEBUG_USART1);

	return temp;

#else		//弃用

	return (uint8_t)USART_ReceiveData(DEBUG_USART1);

#endif
}


/** -------------------------- 串口2 -------------------------- */
/**
 * @brief 串口2 GPIO配置
 *
 * @retval 无
 * */
static void Usart2_Config()
{
	//串口2的GPIO时钟
	DEBUG_USART2_GPIO_APBxClkCmd(DEBUG_USART2_GPIO_CLK, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	// 串口2  Tx的GPIO配置为推挽复用输出模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_InitStructure.GPIO_Pin = DEBUG_USART2_TX_GPIO_PIN;
	GPIO_Init(DEBUG_USART2_TX_GPIO_PORT, &GPIO_InitStructure);

	// 串口2 Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART2_RX_GPIO_PIN;
	GPIO_Init(DEBUG_USART2_RX_GPIO_PORT, &GPIO_InitStructure);
}

/**
 * @brief 串口2 初始化
 *
 * @param baudRate 串口2 的波特率设置
 *
 * @retval 无
 * */
void Usart2_Init(uint32_t baudRate)
{
	//判断是否为重定义printf的Usart
	if (DEBUG_printf_Usartx == DEBUG_USART2)
	{
#if !IS_MDK      //非MDK时的配置

		//缓冲区为0，一有数据就发
		setvbuf(stdout, NULL, _IONBF, 0);

#endif
	}

	USART_InitTypeDef USART_InitStructure;

	//打开串口1的时钟
	DEBUG_USART2_APBxClkCmd(DEBUG_USART2_CLK, ENABLE);

	// 配置串口1的工作参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;								// 配置 帧数据字长
	USART_InitStructure.USART_StopBits = USART_StopBits_1;									// 配置停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;										// 配置校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;			// 配置硬件流控制（无硬件流控制）
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;							// 配置工作模式，收发一起使能
	USART_InitStructure.USART_BaudRate = baudRate;											// 配置波特率

	USART_Init(DEBUG_USART2, &USART_InitStructure);

	//初始化串口1的GPIO
	Usart2_Config();

	//使能串口
	USART_Cmd(DEBUG_USART2, ENABLE);


	//当Usart2为printf重定义时，刷新输出缓冲区
	if (DEBUG_printf_Usartx == DEBUG_USART2)
	{
#if !IS_MDK      //非MDK时的配置

		printf("\n");   //刷新输出缓冲区【测试结果，根据实际需要更改】

#endif
	}
}

/**
 * @brief 使用串口1 发送一字节数据
 * @param data 发送的一字节数据
 * @return 无
 * */
void Usart2_SendByte(const uint8_t data) {
	/** 发送一个字节数据到USART */
	USART_SendData(DEBUG_USART2, data);

	/** 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(DEBUG_USART2, USART_FLAG_TXE) == RESET);
}

/**
 * @brief 使用串口1 发送两字节数据
 * @param data 发送的两字节数据 uint16_t
 * @return 无
 * */
void Usart2_Send2Byte(const uint16_t data) {
	//发送高八位数据
	Usart2_SendByte((data & 0xff00) >> 8);

	//发送低八位数据
	Usart2_SendByte(data & 0x00ff);
}

/**
 * @brief 使用串口1 发送数组
 * @param array 发送的数组
 * @param len array的元素个数 0 - len, 【len不可超过数组元素个数】
 * @return 无
 * */
void Usart2_SendArray(const uint8_t *array, uint32_t len) {
	uint32_t i = 0;
	//将数组中的数据全部发送
	for (i = 0; i < len; ++i) {
		Usart2_SendByte(array[i]);
	}

	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART2, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 发送字符串，遇到'\0'停止，发送出去的字符串末尾有'\0'
 * @param str 发送的字符串
 * @return 无
 * */
void Usart2_SendString(const uint8_t *str) {
	while (*str != '\0') {
		Usart2_SendByte(*str++);
	}
	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART2, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 等待接收一字节数据
 *
 * @retval 返回接收到的数据
 *
 * @note 如果未接收到将会等待接收，这将会导致程序卡死，请注意使用
 * */
uint8_t Usart2_ReceiveByte() {
#if 1
	static uint8_t temp;

	while (USART_GetFlagStatus(DEBUG_USART2, USART_FLAG_RXNE) == RESET);
	temp = (uint8_t) USART_ReceiveData(DEBUG_USART2);

	return temp;

#else		//弃用

	return (uint8_t)USART_ReceiveData(DEBUG_USART2);

#endif
}

/** -------------------------- 串口3 -------------------------- */

/**
 * @brief 串口3 GPIO配置
 *
 * @retval 无
 * */
static void Usart3_Config()
{
	//串口1的GPIO时钟
	DEBUG_USART3_GPIO_APBxClkCmd(DEBUG_USART3_GPIO_CLK, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	// 将USART Tx的GPIO配置为推挽复用输出模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART3_TX_GPIO_PIN;
	GPIO_Init(DEBUG_USART3_TX_GPIO_PORT, &GPIO_InitStructure);

	// 串口2 Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART3_RX_GPIO_PIN;
	GPIO_Init(DEBUG_USART3_RX_GPIO_PORT, &GPIO_InitStructure);
}

/**
 * @brief 串口3 初始化
 *
 * @param baudRate 串口3 的波特率设置
 *
 * @retval 无
 * */
void Usart3_Init(uint32_t baudRate)
{
	//判断是否为重定义printf的Usart
	if (DEBUG_printf_Usartx == DEBUG_USART3)
	{
#if !IS_MDK      //非MDK时的配置

		//缓冲区为0，一有数据就发
		setvbuf(stdout, NULL, _IONBF, 0);

#endif
	}

	USART_InitTypeDef USART_InitStructure;

	//打开串口1的时钟
	DEBUG_USART3_APBxClkCmd(DEBUG_USART3_CLK, ENABLE);

	// 配置串口1的工作参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;								// 配置 帧数据字长
	USART_InitStructure.USART_StopBits = USART_StopBits_1;									// 配置停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;										// 配置校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;			// 配置硬件流控制（无硬件流控制）
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;							// 配置工作模式，收发一起使能
	USART_InitStructure.USART_BaudRate = baudRate;											// 配置波特率

	USART_Init(DEBUG_USART3, &USART_InitStructure);

	//使能串口
	USART_Cmd(DEBUG_USART3, ENABLE);

	//初始化串口1的GPIO
	Usart3_Config();

	//当Usart3为printf重定义时，刷新输出缓冲区
	if (DEBUG_printf_Usartx == DEBUG_USART3)
	{
#if !IS_MDK      //非MDK时的配置

		printf("\n");   //刷新输出缓冲区【测试结果，根据实际需要更改】

#endif
	}
}

/**
 * @brief 使用串口1 发送一字节数据
 * @param data 发送的一字节数据
 * @return 无
 * */
void Usart3_SendByte(const uint8_t data) {
	/** 发送一个字节数据到USART */
	USART_SendData(DEBUG_USART3, data);

	/** 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(DEBUG_USART3, USART_FLAG_TXE) == RESET);
}

/**
 * @brief 使用串口1 发送两字节数据
 * @param data 发送的两字节数据 uint16_t
 * @return 无
 * */
void Usart3_Send2Byte(const uint16_t data) {
	//发送高八位数据
	Usart3_SendByte((data & 0xff00) >> 8);

	//发送低八位数据
	Usart3_SendByte(data & 0x00ff);
}

/**
 * @brief 使用串口1 发送数组
 * @param array 发送的数组
 * @param len array的元素个数 0 - len, 【len不可超过数组元素个数】
 * @return 无
 * */
void Usart3_SendArray(const uint8_t *array, uint32_t len) {
	uint32_t i = 0;
	//将数组中的数据全部发送
	for (i = 0; i < len; ++i) {
		Usart3_SendByte(array[i]);
	}

	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART3, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 发送字符串，遇到'\0'停止，发送出去的字符串末尾有'\0'
 * @param str 发送的字符串
 * @return 无
 * */
void Usart3_SendString(const uint8_t *str) {
	while (*str != '\0') {
		Usart3_SendByte(*str++);
	}
	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART3, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 等待接收一字节数据
 *
 * @retval 返回接收到的数据
 *
 * @note 如果未接收到将会等待接收一字节，这将会导致程序卡死，
 * 		 请注意使用当接收到多字节数据时，会导致多余的字节滞留输出缓冲区，下次调用接收函数时，会接收到滞留的字节数据，且存在不确定性。
 * 		 不建议使用该函数，建议使用原版 USART_ReceiveData 配合 USART_GetFlagStatus 使用
 * */
uint8_t Usart3_ReceiveByte() {
#if 1
	static uint8_t temp;
	while (USART_GetFlagStatus(DEBUG_USART3, USART_FLAG_RXNE) == RESET);
	temp = (uint8_t) USART_ReceiveData(DEBUG_USART3);

	return temp;

#else		//弃用

	return (uint8_t)USART_ReceiveData(DEBUG_USART3);

#endif
}

/** -------------------------- 串口4 -------------------------- */

/**
 * @brief 串口4 GPIO配置
 *
 * @retval 无
 * */
static void Usart4_Config()
{
	//串口1的GPIO时钟
	DEBUG_USART4_GPIO_APBxClkCmd(DEBUG_USART4_GPIO_CLK, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	// 将USART Tx的GPIO配置为推挽复用输出模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART4_TX_GPIO_PIN;
	GPIO_Init(DEBUG_USART4_TX_GPIO_PORT, &GPIO_InitStructure);

	// 串口2 Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART4_RX_GPIO_PIN;
	GPIO_Init(DEBUG_USART4_RX_GPIO_PORT, &GPIO_InitStructure);
}

/**
 * @brief 串口4 初始化
 *
 * @param baudRate 串口4 的波特率设置
 *
 * @retval 无
 * */
void Usart4_Init(uint32_t baudRate)
{
	//判断是否为重定义printf的Usart
	if (DEBUG_printf_Usartx == DEBUG_USART4)
	{
#if !IS_MDK      //非MDK时的配置

		//缓冲区为0，一有数据就发
		setvbuf(stdout, NULL, _IONBF, 0);

#endif
	}

	USART_InitTypeDef USART_InitStructure;

	//打开串口1的时钟
	DEBUG_USART4_APBxClkCmd(DEBUG_USART4_CLK, ENABLE);

	// 配置串口1的工作参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;								// 配置 帧数据字长
	USART_InitStructure.USART_StopBits = USART_StopBits_1;									// 配置停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;										// 配置校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;			// 配置硬件流控制（无硬件流控制）
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;							// 配置工作模式，收发一起使能
	USART_InitStructure.USART_BaudRate = baudRate;											// 配置波特率

	USART_Init(DEBUG_USART4, &USART_InitStructure);

	//使能串口
	USART_Cmd(DEBUG_USART4, ENABLE);

	//初始化串口1的GPIO
	Usart4_Config();

	//当Usart4为printf重定义时，刷新输出缓冲区
	if (DEBUG_printf_Usartx == DEBUG_USART4)
	{
#if !IS_MDK      //非MDK时的配置

		printf("\n");   //刷新输出缓冲区【测试结果，根据实际需要更改】

#endif
	}
}

/**
 * @brief 使用串口1 发送一字节数据
 * @param data 发送的一字节数据
 * @return 无
 * */
void Usart4_SendByte(const uint8_t data) {
	/** 发送一个字节数据到USART */
	USART_SendData(DEBUG_USART4, data);

	/** 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(DEBUG_USART4, USART_FLAG_TXE) == RESET);
}

/**
 * @brief 使用串口1 发送两字节数据
 * @param data 发送的两字节数据 uint16_t
 * @return 无
 * */
void Usart4_Send2Byte(const uint16_t data) {
	//发送高八位数据
	Usart4_SendByte((data & 0xff00) >> 8);

	//发送低八位数据
	Usart4_SendByte(data & 0x00ff);
}

/**
 * @brief 使用串口1 发送数组
 * @param array 发送的数组
 * @param len array的元素个数 0 - len, 【len不可超过数组元素个数】
 * @return 无
 * */
void Usart4_SendArray(const uint8_t *array, uint32_t len) {
	uint32_t i = 0;
	//将数组中的数据全部发送
	for (i = 0; i < len; ++i) {
		Usart4_SendByte(array[i]);
	}

	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART4, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 发送字符串，遇到'\0'停止，发送出去的字符串末尾有'\0'
 * @param str 发送的字符串
 * @return 无
 * */
void Usart4_SendString(const uint8_t *str) {
	while (*str != '\0') {
		Usart4_SendByte(*str++);
	}
	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART4, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 等待接收一字节数据
 *
 * @retval 返回接收到的数据
 *
 * @note 如果未接收到将会等待接收一字节，这将会导致程序卡死，
 * 		 请注意使用当接收到多字节数据时，会导致多余的字节滞留输出缓冲区，下次调用接收函数时，会接收到滞留的字节数据，且存在不确定性。
 * 		 不建议使用该函数，建议使用原版 USART_ReceiveData 配合 USART_GetFlagStatus 使用
 * */
uint8_t Usart4_ReceiveByte() {
#if 1
	static uint8_t temp;
	while (USART_GetFlagStatus(DEBUG_USART4, USART_FLAG_RXNE) == RESET);
	temp = (uint8_t) USART_ReceiveData(DEBUG_USART4);

	return temp;

#else		//弃用

	return (uint8_t)USART_ReceiveData(DEBUG_USART4);

#endif
}

/** -------------------------- 串口4 -------------------------- */

/**
 * @brief 串口5 GPIO配置
 *
 * @retval 无
 * */
static void Usart5_Config()
{
	//串口1的GPIO时钟
	DEBUG_USART5_GPIO_APBxClkCmd(DEBUG_USART5_GPIO_CLK, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	// 将USART Tx的GPIO配置为推挽复用输出模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART5_TX_GPIO_PIN;
	GPIO_Init(DEBUG_USART5_TX_GPIO_PORT, &GPIO_InitStructure);

	// 串口2 Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART5_RX_GPIO_PIN;
	GPIO_Init(DEBUG_USART5_RX_GPIO_PORT, &GPIO_InitStructure);
}

/**
 * @brief 串口5 初始化
 *
 * @param baudRate 串口4 的波特率设置
 *
 * @retval 无
 * */
void Usart5_Init(uint32_t baudRate)
{
	//判断是否为重定义printf的Usart
	if (DEBUG_printf_Usartx == DEBUG_USART5)
	{
#if !IS_MDK      //非MDK时的配置

		//缓冲区为0，一有数据就发
		setvbuf(stdout, NULL, _IONBF, 0);

#endif
	}

	USART_InitTypeDef USART_InitStructure;

	//打开串口1的时钟
	DEBUG_USART5_APBxClkCmd(DEBUG_USART5_CLK, ENABLE);

	// 配置串口1的工作参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;								// 配置 帧数据字长
	USART_InitStructure.USART_StopBits = USART_StopBits_1;									// 配置停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;										// 配置校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;			// 配置硬件流控制（无硬件流控制）
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;							// 配置工作模式，收发一起使能
	USART_InitStructure.USART_BaudRate = baudRate;											// 配置波特率

	USART_Init(DEBUG_USART5, &USART_InitStructure);

	//使能串口
	USART_Cmd(DEBUG_USART5, ENABLE);

	//初始化串口1的GPIO
	Usart5_Config();

	//当Usart5为printf重定义时，刷新输出缓冲区
	if (DEBUG_printf_Usartx == DEBUG_USART5)
	{
#if !IS_MDK      //非MDK时的配置

		printf("\n");   //刷新输出缓冲区【测试结果，根据实际需要更改】

#endif
	}
}

/**
 * @brief 使用串口1 发送一字节数据
 * @param data 发送的一字节数据
 * @return 无
 * */
void Usart5_SendByte(const uint8_t data) {
	/** 发送一个字节数据到USART */
	USART_SendData(DEBUG_USART5, data);

	/** 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(DEBUG_USART5, USART_FLAG_TXE) == RESET);
}

/**
 * @brief 使用串口1 发送两字节数据
 * @param data 发送的两字节数据 uint16_t
 * @return 无
 * */
void Usart5_Send2Byte(const uint16_t data) {
	//发送高八位数据
	Usart5_SendByte((data & 0xff00) >> 8);

	//发送低八位数据
	Usart5_SendByte(data & 0x00ff);
}

/**
 * @brief 使用串口1 发送数组
 * @param array 发送的数组
 * @param len array的元素个数 0 - len, 【len不可超过数组元素个数】
 * @return 无
 * */
void Usart5_SendArray(const uint8_t *array, uint32_t len) {
	uint32_t i = 0;
	//将数组中的数据全部发送
	for (i = 0; i < len; ++i) {
		Usart5_SendByte(array[i]);
	}

	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART5, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 发送字符串，遇到'\0'停止，发送出去的字符串末尾有'\0'
 * @param str 发送的字符串
 * @return 无
 * */
void Usart5_SendString(const uint8_t *str) {
	while (*str != '\0') {
		Usart5_SendByte(*str++);
	}
	//等待数据全部发送完毕
	while (USART_GetFlagStatus(DEBUG_USART5, USART_FLAG_TC) == RESET);        //USART_FLAG_TC发送一连串数据
}

/**
 * @brief 使用串口1 等待接收一字节数据
 *
 * @retval 返回接收到的数据
 *
 * @note 如果未接收到将会等待接收一字节，这将会导致程序卡死，
 * 		 请注意使用当接收到多字节数据时，会导致多余的字节滞留输出缓冲区，下次调用接收函数时，会接收到滞留的字节数据，且存在不确定性。
 * 		 不建议使用该函数，建议使用原版 USART_ReceiveData 配合 USART_GetFlagStatus 使用
 * */
uint8_t Usart5_ReceiveByte() {
#if 1
	static uint8_t temp;
	while (USART_GetFlagStatus(DEBUG_USART5, USART_FLAG_RXNE) == RESET);
	temp = (uint8_t) USART_ReceiveData(DEBUG_USART5);

	return temp;

#else		//弃用

	return (uint8_t)USART_ReceiveData(DEBUG_USART5);

#endif
}





